/**
 ******************************************************************************
 * @file           : bsp_can.c
 * @brief          : CAN Driver Implementation (STM32F1xx)
 ******************************************************************************
 * @attention
 *
 * CAN总线驱动程序实现文件
 * 提供CAN通信功能
 * 支持中断接收和循环缓冲区管理
 *
 ******************************************************************************
 */

/* Includes ------------------------------------------------------------------*/
#include "./BSP/CAN/bsp_can.h"
#include "./BSP/CAN/bsp_can_config.h"

/* Private includes ----------------------------------------------------------*/
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
static CAN_HandleTypeDef sg_can_handle;                     /*!< CAN句柄 */
static volatile CAN_State_e sg_can_state = CAN_STATE_IDLE;  /*!< CAN当前状态 */
static volatile uint8_t sg_can_initialized = 0;             /*!< 初始化标志 */

/* 接收缓冲区 */
static CAN_Message_t sg_can_rx_buffer[CAN_RX_BUF_SIZE];     /*!< 接收缓冲区 */
static volatile uint16_t sg_can_rx_head = 0;                /*!< 接收缓冲区头指针 */
static volatile uint16_t sg_can_rx_tail = 0;                /*!< 接收缓冲区尾指针 */

/* Private function prototypes -----------------------------------------------*/
static void can_gpio_init(void);
static void can_peripheral_init(void);
static void can_nvic_init(void);
static uint8_t can_rx_buffer_put(const CAN_Message_t *msg);
static uint8_t can_rx_buffer_get(CAN_Message_t *msg);

/* Private functions ---------------------------------------------------------*/

/**
 * @brief       CAN GPIO初始化
 *
 * @param       无
 *
 * @retval      无
 *
 * @note        配置TX和RX引脚
 */
static void can_gpio_init(void)
{
    GPIO_InitTypeDef gpio_init_struct;

    /* 使能GPIO时钟 */
    CAN_TX_GPIO_CLK_ENABLE();
    CAN_RX_GPIO_CLK_ENABLE();

    /* 配置TX引脚 - 复用推挽输出 */
    gpio_init_struct.Pin = CAN_TX_GPIO_PIN;
    gpio_init_struct.Mode = GPIO_MODE_AF_PP;
    gpio_init_struct.Pull = GPIO_PULLUP;
    gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(CAN_TX_GPIO_PORT, &gpio_init_struct);

    /* 配置RX引脚 - 浮空输入 */
    gpio_init_struct.Pin = CAN_RX_GPIO_PIN;
    gpio_init_struct.Mode = GPIO_MODE_INPUT;
    gpio_init_struct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(CAN_RX_GPIO_PORT, &gpio_init_struct);
}

/**
 * @brief       CAN外设初始化
 *
 * @param       无
 *
 * @retval      无
 *
 * @note        配置CAN工作模式和波特率
 */
static void can_peripheral_init(void)
{
    /* 使能CAN时钟 */
    CAN_CANx_CLK_ENABLE();

    /* 配置CAN参数 */
    sg_can_handle.Instance = CAN_CANx;
    sg_can_handle.Init.Prescaler = CAN_PRESCALER;
    sg_can_handle.Init.Mode = CAN_MODE;
    sg_can_handle.Init.SyncJumpWidth = CAN_SJW;
    sg_can_handle.Init.TimeSeg1 = CAN_TIME_SEG1;
    sg_can_handle.Init.TimeSeg2 = CAN_TIME_SEG2;
    sg_can_handle.Init.TimeTriggeredMode = DISABLE;
    sg_can_handle.Init.AutoBusOff = ENABLE;
    sg_can_handle.Init.AutoWakeUp = DISABLE;
    sg_can_handle.Init.AutoRetransmission = ENABLE;
    sg_can_handle.Init.ReceiveFifoLocked = DISABLE;
    sg_can_handle.Init.TransmitFifoPriority = DISABLE;

    /* 初始化CAN */
    if (HAL_CAN_Init(&sg_can_handle) != HAL_OK)
    {
        log_e("CAN外设初始化失败");
        return;
    }

    /* 启动CAN */
    if (HAL_CAN_Start(&sg_can_handle) != HAL_OK)
    {
        log_e("CAN启动失败");
        return;
    }

    /* 激活通知 */
    if (HAL_CAN_ActivateNotification(&sg_can_handle, CAN_IT_RX_FIFO0_MSG_PENDING) != HAL_OK)
    {
        log_e("CAN中断激活失败");
        return;
    }
}

/**
 * @brief       CAN中断初始化
 *
 * @param       无
 *
 * @retval      无
 *
 * @note        配置NVIC中断优先级
 */
static void can_nvic_init(void)
{
    HAL_NVIC_SetPriority(CAN_RX_IRQn, 1, 0);
    HAL_NVIC_EnableIRQ(CAN_RX_IRQn);
}

/**
 * @brief       将消息放入接收缓冲区
 *
 * @param[in]   msg 消息指针
 *
 * @retval      1 成功
 * @retval      0 失败(缓冲区满)
 *
 * @note        内部函数，在中断中调用
 */
static uint8_t can_rx_buffer_put(const CAN_Message_t *msg)
{
    uint16_t next_head;

    if (msg == NULL)
    {
        return 0;
    }

    /* 计算下一个头指针位置 */
    next_head = (sg_can_rx_head + 1) % CAN_RX_BUF_SIZE;

    /* 检查缓冲区是否已满 */
    if (next_head == sg_can_rx_tail)
    {
        log_w("CAN接收缓冲区满");
        return 0;
    }

    /* 存入消息 */
    sg_can_rx_buffer[sg_can_rx_head] = *msg;
    sg_can_rx_head = next_head;

    return 1;
}

/**
 * @brief       从接收缓冲区取出消息
 *
 * @param[out]  msg 消息指针
 *
 * @retval      1 成功
 * @retval      0 失败(缓冲区空)
 *
 * @note        内部函数
 */
static uint8_t can_rx_buffer_get(CAN_Message_t *msg)
{
    if (msg == NULL)
    {
        return 0;
    }

    /* 检查缓冲区是否为空 */
    if (sg_can_rx_head == sg_can_rx_tail)
    {
        return 0;
    }

    /* 取出消息 */
    *msg = sg_can_rx_buffer[sg_can_rx_tail];
    sg_can_rx_tail = (sg_can_rx_tail + 1) % CAN_RX_BUF_SIZE;

    return 1;
}

/* Exported functions --------------------------------------------------------*/

/**
 * @brief       CAN初始化
 *
 * @param       无
 *
 * @retval      无
 *
 * @note        初始化CAN GPIO、外设和中断
 */
void can_init(void)
{
    if (sg_can_initialized)
    {
        log_w("CAN已经初始化");
        return;
    }

    /* 初始化GPIO */
    can_gpio_init();

    /* 初始化CAN外设 */
    can_peripheral_init();

    /* 初始化中断 */
    can_nvic_init();

    /* 配置默认过滤器(接收所有消息) */
    can_filter_config(0, 0);

    /* 清空接收缓冲区 */
    sg_can_rx_head = 0;
    sg_can_rx_tail = 0;

    /* 设置状态 */
    sg_can_state = CAN_STATE_IDLE;
    sg_can_initialized = 1;

    log_i("CAN初始化完成");
    log_i("  波特率配置: Prescaler=%d, BS1=%d, BS2=%d", 
          CAN_PRESCALER, CAN_TIME_SEG1 >> 16, CAN_TIME_SEG2 >> 20);
}

/**
 * @brief       CAN反初始化
 *
 * @param       无
 *
 * @retval      无
 *
 * @note        释放CAN资源
 */
void can_deinit(void)
{
    if (!sg_can_initialized)
    {
        return;
    }

    /* 停止CAN */
    HAL_CAN_Stop(&sg_can_handle);

    /* 反初始化CAN */
    HAL_CAN_DeInit(&sg_can_handle);

    /* 反初始化GPIO */
    HAL_GPIO_DeInit(CAN_TX_GPIO_PORT, CAN_TX_GPIO_PIN);
    HAL_GPIO_DeInit(CAN_RX_GPIO_PORT, CAN_RX_GPIO_PIN);

    /* 禁用中断 */
    HAL_NVIC_DisableIRQ(CAN_RX_IRQn);

    /* 清除标志 */
    sg_can_initialized = 0;
    sg_can_state = CAN_STATE_IDLE;

    log_i("CAN已反初始化");
}

/**
 * @brief       配置CAN过滤器
 *
 * @param[in]   id   过滤器ID
 * @param[in]   mask 过滤器掩码
 *
 * @retval      CAN_OK         配置成功
 * @retval      CAN_ERROR_HAL   HAL库错误
 *
 * @note        使用标识符列表模式
 * @note        id=0, mask=0表示接收所有消息
 */
CAN_Error_e can_filter_config(uint32_t id, uint32_t mask)
{
    CAN_FilterTypeDef filter_config;

    if (!sg_can_initialized)
    {
        log_e("CAN未初始化");
        return CAN_ERROR_PARAM;
    }

    /* 配置过滤器 */
    filter_config.FilterBank = 0;
    filter_config.FilterMode = CAN_FILTERMODE_IDMASK;
    filter_config.FilterScale = CAN_FILTERSCALE_32BIT;
    filter_config.FilterIdHigh = (id << 5) >> 16;
    filter_config.FilterIdLow = (id << 5) & 0xFFFF;
    filter_config.FilterMaskIdHigh = (mask << 5) >> 16;
    filter_config.FilterMaskIdLow = (mask << 5) & 0xFFFF;
    filter_config.FilterFIFOAssignment = CAN_RX_FIFO;
    filter_config.FilterActivation = ENABLE;

    if (HAL_CAN_ConfigFilter(&sg_can_handle, &filter_config) != HAL_OK)
    {
        log_e("过滤器配置失败");
        return CAN_ERROR_HAL;
    }

    log_d("过滤器配置成功: ID=0x%08X, Mask=0x%08X", id, mask);
    return CAN_OK;
}

/**
 * @brief       禁用CAN过滤器
 *
 * @param       无
 *
 * @retval      CAN_OK         禁用成功
 * @retval      CAN_ERROR_HAL   HAL库错误
 *
 * @note        禁用后将不接收任何消息
 */
CAN_Error_e can_filter_disable(void)
{
    CAN_FilterTypeDef filter_config;

    if (!sg_can_initialized)
    {
        log_e("CAN未初始化");
        return CAN_ERROR_PARAM;
    }

    /* 禁用过滤器 */
    filter_config.FilterBank = 0;
    filter_config.FilterActivation = DISABLE;

    if (HAL_CAN_ConfigFilter(&sg_can_handle, &filter_config) != HAL_OK)
    {
        log_e("过滤器禁用失败");
        return CAN_ERROR_HAL;
    }

    log_d("过滤器已禁用");
    return CAN_OK;
}

/**
 * @brief       发送CAN消息
 *
 * @param[in]   msg 消息指针
 *
 * @retval      CAN_OK         发送成功
 * @retval      CAN_ERROR_PARAM 参数错误
 * @retval      CAN_ERROR_HAL   HAL库错误
 *
 * @note        支持标准帧和扩展帧
 */
CAN_Error_e can_send(const CAN_Message_t *msg)
{
    CAN_TxHeaderTypeDef tx_header;
    uint32_t mailbox;

    /* 参数检查 */
    if (msg == NULL)
    {
        log_w("消息指针为NULL");
        return CAN_ERROR_PARAM;
    }

    if (msg->dlc > 8)
    {
        log_w("数据长度无效: %d", msg->dlc);
        return CAN_ERROR_PARAM;
    }

    if (!sg_can_initialized)
    {
        log_e("CAN未初始化");
        return CAN_ERROR_PARAM;
    }

    sg_can_state = CAN_STATE_TX;

    /* 配置发送头 */
    if (msg->ide == 0)
    {
        /* 标准帧 */
        tx_header.StdId = msg->id;
        tx_header.IDE = CAN_ID_STD;
    }
    else
    {
        /* 扩展帧 */
        tx_header.ExtId = msg->id;
        tx_header.IDE = CAN_ID_EXT;
    }

    tx_header.RTR = msg->rtr ? CAN_RTR_REMOTE : CAN_RTR_DATA;
    tx_header.DLC = msg->dlc;
    tx_header.TransmitGlobalTime = DISABLE;

    /* 发送消息 */
    if (HAL_CAN_AddTxMessage(&sg_can_handle, &tx_header, (uint8_t *)msg->data, &mailbox) != HAL_OK)
    {
        log_w("CAN发送失败");
        sg_can_state = CAN_STATE_ERROR;
        return CAN_ERROR_HAL;
    }

    sg_can_state = CAN_STATE_IDLE;
    log_d("CAN发送成功: ID=0x%08X, DLC=%d", msg->id, msg->dlc);

    return CAN_OK;
}

/**
 * @brief       发送CAN标准帧
 *
 * @param[in]   id   CAN ID(11位)
 * @param[in]   data 数据指针
 * @param[in]   len  数据长度(0-8)
 *
 * @retval      CAN_OK         发送成功
 * @retval      CAN_ERROR_PARAM 参数错误
 * @retval      CAN_ERROR_HAL   HAL库错误
 *
 * @note        简化接口，用于发送标准帧
 */
CAN_Error_e can_send_std(uint32_t id, const uint8_t *data, uint8_t len)
{
    CAN_Message_t msg;
    uint8_t i;

    /* 参数检查 */
    if (data == NULL || len > 8)
    {
        log_w("发送参数错误");
        return CAN_ERROR_PARAM;
    }

    /* 组装消息 */
    msg.id = id;
    msg.ide = 0;
    msg.rtr = 0;
    msg.dlc = len;

    for (i = 0; i < len; i++)
    {
        msg.data[i] = data[i];
    }

    return can_send(&msg);
}

/**
 * @brief       发送CAN扩展帧
 *
 * @param[in]   id   CAN ID(29位)
 * @param[in]   data 数据指针
 * @param[in]   len  数据长度(0-8)
 *
 * @retval      CAN_OK         发送成功
 * @retval      CAN_ERROR_PARAM 参数错误
 * @retval      CAN_ERROR_HAL   HAL库错误
 *
 * @note        简化接口，用于发送扩展帧
 */
CAN_Error_e can_send_ext(uint32_t id, const uint8_t *data, uint8_t len)
{
    CAN_Message_t msg;
    uint8_t i;

    /* 参数检查 */
    if (data == NULL || len > 8)
    {
        log_w("发送参数错误");
        return CAN_ERROR_PARAM;
    }

    /* 组装消息 */
    msg.id = id;
    msg.ide = 1;
    msg.rtr = 0;
    msg.dlc = len;

    for (i = 0; i < len; i++)
    {
        msg.data[i] = data[i];
    }

    return can_send(&msg);
}

/**
 * @brief       接收CAN消息
 *
 * @param[out]  msg 消息指针
 *
 * @retval      CAN_OK         接收成功
 * @retval      CAN_ERROR_PARAM 参数错误
 * @retval      CAN_ERROR_EMPTY 缓冲区空
 *
 * @note        从接收缓冲区读取消息
 */
CAN_Error_e can_receive(CAN_Message_t *msg)
{
    /* 参数检查 */
    if (msg == NULL)
    {
        log_w("消息指针为NULL");
        return CAN_ERROR_PARAM;
    }

    if (!sg_can_initialized)
    {
        log_e("CAN未初始化");
        return CAN_ERROR_PARAM;
    }

    /* 从缓冲区读取 */
    if (!can_rx_buffer_get(msg))
    {
        return CAN_ERROR_EMPTY;
    }

    log_d("CAN接收: ID=0x%08X, DLC=%d", msg->id, msg->dlc);
    return CAN_OK;
}

/**
 * @brief       获取可用消息数量
 *
 * @param       无
 *
 * @retval      可用消息数
 *
 * @note        用于判断是否有消息可读
 */
uint16_t can_available(void)
{
    uint16_t count;

    if (sg_can_rx_head >= sg_can_rx_tail)
    {
        count = sg_can_rx_head - sg_can_rx_tail;
    }
    else
    {
        count = CAN_RX_BUF_SIZE - sg_can_rx_tail + sg_can_rx_head;
    }

    return count;
}

/**
 * @brief       获取CAN当前状态
 *
 * @param       无
 *
 * @retval      CAN_State_e 当前状态
 *
 * @note        用于状态监控和调试
 */
CAN_State_e can_get_state(void)
{
    return sg_can_state;
}

/**
 * @brief       检查CAN总线是否关闭
 *
 * @param       无
 *
 * @retval      1 总线关闭
 * @retval      0 正常
 *
 * @note        用于检测总线故障
 */
uint8_t can_is_bus_off(void)
{
    uint32_t esr;

    if (!sg_can_initialized)
    {
        return 0;
    }

    esr = sg_can_handle.Instance->ESR;
    return ((esr & CAN_ESR_BOFF) != 0);
}

/**
 * @brief       打印CAN当前状态（用于调试）
 *
 * @param       无
 *
 * @retval      无
 *
 * @note        显示初始化状态、当前状态、配置信息等
 */
void can_print_status(void)
{
    const char *state_str[] = {"IDLE", "BUSY", "TX", "RX", "ERROR"};

    log_i("CAN当前状态:");
    log_i("  初始化状态: %s", sg_can_initialized ? "已初始化" : "未初始化");
    log_i("  当前状态: %s", state_str[sg_can_state]);
    log_i("  接收缓冲区: %d/%d", can_available(), CAN_RX_BUF_SIZE);
    log_i("  总线状态: %s", can_is_bus_off() ? "总线关闭" : "正常");
}

/**
 * @brief       打印CAN消息内容（用于调试）
 *
 * @param[in]   msg 消息指针
 *
 * @retval      无
 *
 * @note        以十六进制格式打印消息
 */
void can_print_message(const CAN_Message_t *msg)
{
    uint8_t i;

    if (msg == NULL)
    {
        log_w("消息指针为NULL");
        return;
    }

    log_i("CAN消息:");
    log_i("  ID: 0x%08X (%s)", msg->id, msg->ide ? "扩展帧" : "标准帧");
    log_i("  类型: %s", msg->rtr ? "远程帧" : "数据帧");
    log_i("  长度: %d", msg->dlc);

    if (msg->dlc > 0 && !msg->rtr)
    {
        log_i("  数据:");
        for (i = 0; i < msg->dlc; i++)
        {
            log_i("    [%d] = 0x%02X", i, msg->data[i]);
        }
    }
}

/**
 * @brief       CAN接收中断回调函数
 *
 * @param       无
 *
 * @retval      无
 *
 * @note        在中断中将接收数据存入缓冲区
 */
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
{
    CAN_RxHeaderTypeDef rx_header;
    CAN_Message_t msg;

    if (hcan->Instance == CAN_CANx)
    {
        /* 从FIFO读取消息 */
        if (HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO, &rx_header, msg.data) == HAL_OK)
        {
            /* 解析消息头 */
            if (rx_header.IDE == CAN_ID_STD)
            {
                msg.id = rx_header.StdId;
                msg.ide = 0;
            }
            else
            {
                msg.id = rx_header.ExtId;
                msg.ide = 1;
            }

            msg.rtr = (rx_header.RTR == CAN_RTR_REMOTE) ? 1 : 0;
            msg.dlc = rx_header.DLC;

            /* 存入缓冲区 */
            can_rx_buffer_put(&msg);
        }
    }
}
